﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace QQ2564874169.Nubbo
{
    public interface IServiceInvoker : IDisposable
    {
        Task<ResponseResult> Invoke(NubboNode node, string serviceName, RequestParam param);
    }

    public class HttpInvoker : IServiceInvoker
    {
        static HttpInvoker()
        {
            ServicePointManager.ServerCertificateValidationCallback += (p1, p2, p3, p4) => true;
            ServicePointManager.DefaultConnectionLimit = int.MaxValue;
            ServicePointManager.CheckCertificateRevocationList = false;
        }

        public void Dispose()
        {

        }

        public async Task<ResponseResult> Invoke(NubboNode node, string serviceName, RequestParam param)
        {
            var host = node.Host.ToLower();
            if (host.StartsWith("http."))
            {
                host = host.Replace("http.", "http://");
            }
            else if (host.StartsWith("https."))
            {
                host = host.Replace("https.", "https://");
            }
            host += ":" + node.Port + "/" + serviceName;

            var req = WebRequest.Create(host) as HttpWebRequest;
            req.Method = "POST";
            req.KeepAlive = false;

            foreach (var item in param.Header)
            {
                req.Headers.Add(item.Key, item.Value);
            }

            if (param.Param.Count > 0)
            {
                var data = Encoding.UTF8.GetBytes(string.Join("&", param.Param.Select(i => i.Key + "=" + i.Value)));
                req.ContentType = "application/x-www-form-urlencoded; charset=" + Encoding.UTF8.BodyName.ToLower();
                req.ContentLength = data.Length;
                using (var sm = req.GetRequestStream())
                {
                    sm.Write(data, 0, data.Length);
                }
            }
            WebResponse response;
            var status = (int) HttpStatusCode.OK;
            try
            {
                response = await req.GetResponseAsync();
            }
            catch (WebException ex)
            {
                status = (int)ex.Status;
                if (status != (int) HttpStatusCode.InternalServerError)
                    throw;
                response = ex.Response;
            }
            var result = new ResponseResult();
            foreach (var key in response.Headers.AllKeys)
            {
                var value = response.Headers.GetValues(key);
                if (value != null)
                    result.Header.Add(key, value.Last());
            }
            if (response.ContentLength > 0)
            {
                result.Data = new byte[response.ContentLength];
                using (var sm = response.GetResponseStream())
                {
                    sm.Read(result.Data, 0, result.Data.Length);
                }
                if ((int) HttpStatusCode.InternalServerError == status)
                {
                    result.Error = Encoding.UTF8.GetString(result.Data);
                    result.Data = null;
                }
            }
            return result;
        }
    }
}
